// import Dep from "./Dep";

import nextTick from "../utils/nextTick"
import { pushTarget, removeTarget } from "./Dep"

// var uid = 0
// export default class Watcher{
//     constructor(target,expression,callback,options){
//         this.id = uid++
//         this.target = target
        
//         if(typeof expression === 'function'){
//             console.log('用来更新试图');
//         } else {
//             this.getter = parsePath(expression)
//         }
//         this.callback = callback
//         this.options  = options
//         this.value = this.get()
   
//     }

//     update(){
//         this.run()
//     }
//     get(){
//         // 让全局的Dep.target设置为watcher本身，那么就是进入依赖搜集阶段
//         Dep.target = this
//         const obj = this.target
//         var value
//         try {
//             value = this.getter(obj)
//         } finally{
//             Dep.target = null
//         }
//         console.log(value);
//         return value
//     }
//     run(){
//         this.getAndInvoke(this.callback)
//     }
//     getAndInvoke(cb){
//         const value = this.get()
//         if(value !== this.value || typeof value == 'object'){
//             const oldValue = this.value
//             this.value = value
//             cb(this.target,value,oldValue)
//         }
//     }
// }
function parsePath(expression) {
    var segments = expression.split('.')

    return (obj) =>{
        for (let i = 0; i < segments.length; i++) {
            if(!obj) return
            obj = obj[segments[i]];
        }
        return obj
    }
}

let id = 0
class Watcher{
    constructor(vm,updataComponent,cb,options){
        this.vm = vm
        this.exprOrfn = updataComponent
        this.cb = cb
        this.options = options
        // computed
        this.lazy = options.lazy // lazy： 这个watcher中有lazy为true.说明他是计算属性
        this.dirty = this.lazy // dirty： 表示用户是否执行 计算属性
        this.id = id++
        this.deps = []
        this.user = !!options.user
        this.depsId = new Set()
        // 是函数的话 就表示是通过计算属性和watch属性表达式。
        if(typeof updataComponent === 'function'){
            this.getter = updataComponent // 用来更新试图
        } else {
            // {a, b, c}
            // updataComponent 不是函数的话，就是字符串。要把它处理成函数
            this.getter = function () {
                let path = this.exprOrfn.split('.')
                let obj = vm
                
                for (let i = 0; i < path.length; i++) {
                    obj = obj[path[i]]
                }
                return obj
            }
        }

        // 更新视图
        // 如果当前watcher是通过计算属性创建的  默认不执行
        this.value = this.lazy ? void 0 : this.get()
    }

    // 初次渲染
    get(){
        pushTarget(this) // 添加watcher
        // 这个地方通过call改变this指向时
        // 是因为getter执行computed的表达式式，this指向的式watcher而不是vm
        const value =  this.getter.call(this.vm)
        removeTarget() // 一出watcher
        return value
    }
    run(){
        // 新值
        let value = this.get()
        let oldValue = this.value
        this.value = value
        // 
        if(this.user){
            this.cb.call(this.vm,oldValue,this.value)
        }
    }
    // 
    updata(){

        // this.getter()
        // 注意不要数据更新后，每次都重新渲染视图
        // this.get()
        if(this.lazy){ // 这个是计算属性的watcher
            this.dirty = true
        } else {
            queueWatcher(this)
        }   
    }

    addDep(dep){
        // 去重
        let id = dep.id
        if(!this.depsId.has(id)){
            this.deps.push(dep)
            this.depsId.add(id)
            dep.addSub(this)
        }
    }

    // computed中调用自己方法的函数
    evaluate(){
        this.value = this.get()
        this.dirty = false
    }

    // 相互收集
    depend(){
        // 搜集watcher ，存放到dep中
        // 并且dep中还会存放watcher
        let i = this.deps.length
        // console.log('走到了这里');
        while (i--) {
            this.deps[i].depend()
        }
    }
}
let queue = [] //将需要批量更新的watcher存放到一个列队中
let has = {}
let pending = false
function flushWatcher() {
    queue.forEach(item=>{
        item.run()
        // item.cb()
     })
     queue = []
     has = {}
     pending = false
}
function queueWatcher(watcher) {
    let id = watcher.id
    // 去重
    if(has[id]==null){
        // 列队处理
        queue.push(watcher)
        has[id] = true
        if(!pending){
            nextTick(flushWatcher)
        }
        pending = true
    }
}
export default Watcher